package builderenum

import (
	"fmt"
	"slices"
	"time"
	"yunj/pkg/yunj/app/enum/stateenum"
	"yunj/pkg/yunj/core/db"
	"yunj/pkg/yunj/core/enum"
	"yunj/pkg/yunj/core/response"

	"github.com/gin-gonic/gin"
)

// 定义事件类型常量
const (
	// 恢复正常
	TABLE_EVENT_TYPE_NORMAL string = "normal"
	// 移入回收站
	TABLE_EVENT_TYPE_RECYLE_BIN string = "recyle_bin"
	// 永久删除
	TABLE_EVENT_TYPE_DELETED string = "deleted"
	// 排序
	TABLE_EVENT_TYPE_SORT string = "sort"
)

// 权限类型
// 实现EnumInerface接口
type Event struct {
	enum.Enum[string]
}

// types.AuthType.GetDescMap()
func (e *Event) AllConstAttrs() map[string]map[string]any {
	return map[string]map[string]any{
		TABLE_EVENT_TYPE_NORMAL: {
			"desc":                "恢复正常",
			"dbStateVal":          stateenum.NORMAL,
			"dbAllowDataStateVal": stateenum.RECYLE_BIN,
		},
		TABLE_EVENT_TYPE_RECYLE_BIN: {
			"desc":                "移入回收站",
			"dbStateVal":          stateenum.RECYLE_BIN,
			"dbAllowDataStateVal": stateenum.NORMAL,
		},
		TABLE_EVENT_TYPE_DELETED: {
			"desc":                "永久删除",
			"dbStateVal":          stateenum.DELETED,
			"dbAllowDataStateVal": stateenum.RECYLE_BIN,
		},
		TABLE_EVENT_TYPE_SORT: {
			"desc": "排序",
		},
	}
}

// instanceCache 存储已经创建的实例
var eventInstanceCache = make(map[string]*Event)

// 根据value获取枚举
func EventByValue(value string) *Event {
	if instance, exists := eventInstanceCache[value]; exists {
		return instance
	}
	e := &Event{}
	enum.SetEnumInstance(&e.Enum, e, value)
	eventInstanceCache[value] = e
	return e
}

var EventEnum *Event = func() *Event {
	e := &Event{}
	enum.SetEnumInstance(&e.Enum, e)
	return e
}()

// 获取映射的数据库state值
func (e *Event) GetDbStateVal() uint8 {
	return e.GetAttr("dbStateVal").(uint8)
}

// 获取映射的数据库允许操作的数据state值
func (e *Event) GetDbAllowDataStateVal() uint8 {
	return e.GetAttr("dbAllowDataStateVal").(uint8)
}

// 判断是否state事件
func (e *Event) IsStateEvent() bool {
	return slices.Contains([]string{TABLE_EVENT_TYPE_NORMAL, TABLE_EVENT_TYPE_RECYLE_BIN, TABLE_EVENT_TYPE_DELETED}, e.Value)
}

// 事件数据库参数
type EventDbParam struct {
	Data  map[string]interface{}
	Where []interface{}
	Datas []map[string]interface{}
}

// 处理事件
// @return ok 是否处理成功
// @return err 处理失败的错误信息
func HandleEvent(ctx *gin.Context, model interface{}, eventCode interface{}, pks []interface{}, handleDbParam func(param *EventDbParam, e *Event, pks []any) error) (res *response.JsonData, err error) {
	if len(pks) <= 0 {
		return
	}
	eventVal, ok := EventEnum.IsValue(eventCode)
	if !ok {
		return
	}
	e := EventByValue(eventVal)
	currTime := time.Now().Format("2006-01-02 15:04:05")
	db := db.Model(model)
	modelPks, err := db.GetTablePrimaryKeys()
	if err != nil {
		return
	}
	if len(modelPks) > 1 {
		err = fmt.Errorf("数据表 %s 有多主键，不适用于此方法", db.GetTableName())
		return
	}
	modelPk := modelPks[0]
	param := &EventDbParam{}
	if slices.Contains([]string{TABLE_EVENT_TYPE_NORMAL, TABLE_EVENT_TYPE_RECYLE_BIN, TABLE_EVENT_TYPE_DELETED}, e.Value) {
		param.Data = map[string]interface{}{
			"state":      e.GetDbStateVal(),
			"updated_at": currTime,
		}
		param.Where = []interface{}{
			[]interface{}{"state = ?", e.GetDbAllowDataStateVal()},
			[]interface{}{"`" + modelPk + "` in ?", pks},
		}
		if handleDbParam != nil {
			err = handleDbParam(param, e, pks)
			if err != nil {
				err = fmt.Errorf("%s失败！%v", e.GetDesc(), err)
				return
			}
		}
		if len(param.Data) <= 0 || len(param.Where) <= 0 {
			return
		}
		err = db.Change(param.Data, param.Where).Error
		if err != nil {
			err = fmt.Errorf("%s失败！%v", e.GetDesc(), err)
			return
		}
		res = response.SuccessJsonData(map[string]any{"reload": true})
		return
	} else if e.Value == TABLE_EVENT_TYPE_SORT {
		param.Datas = make([]map[string]interface{}, 0, len(pks))
		sort := 0
		for _, pkVal := range pks {
			param.Datas = append(param.Datas, map[string]interface{}{
				modelPk:      pkVal,
				"sort":       sort,
				"updated_at": currTime,
			})
			sort++
		}
		if handleDbParam != nil {
			err = handleDbParam(param, e, pks)
			if err != nil {
				err = fmt.Errorf("%s失败！%v", e.GetDesc(), err)
				return
			}
		}
		err = db.BatchChange(param.Datas).Error
		if err != nil {
			err = fmt.Errorf("%s失败！%v", e.GetDesc(), err)
			return
		}
		res = response.SuccessJsonData(map[string]any{"reload": true})
		return
	}
	return
}
